package com.yfkj.sms.es.service.impl;

import com.yfkj.sms.es.model.Message;
import com.yfkj.sms.es.model.pageReq.Page;
import com.yfkj.sms.es.service.repository.DocumentRepository;
import com.yfkj.sms.es.util.*;
import com.yfkj.sms.service.EsBaseService;
import org.apache.dubbo.config.annotation.DubboService;
import org.elasticsearch.action.DocWriteResponse;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.Operator;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.query.*;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.*;

/**
 * @ Author xsd
 * @ crate time 2020/11/22 16:40
 * @ 描述
 */
@DubboService
public class EsServiceImpl<T> implements EsBaseService<T> {
    private Logger log = LoggerFactory.getLogger(getClass());

    @Resource
    private ElasticsearchTemplate elasticsearchTemplate;
    @Resource
    private RestHighLevelClient client;
    @Resource
    private DocumentRepository elasticsearchRepository;

    @Override
    public void createIndex(Class<T> clazz) throws Exception {
        boolean flag = elasticsearchTemplate.createIndex(clazz);
        log.info("创建索引：" + clazz + "，返回结果：" + flag);
    }

    @Override
    public void dropIndex(Class<T> clazz) throws Exception {
        MetaData metaData = IndexTools.getIndexType(clazz);
        String indexname = metaData.getIndexname();
        boolean dropIndex = elasticsearchTemplate.deleteIndex(indexname);
        log.info("删除索引：" + clazz + "，返回结果：" + dropIndex);
    }

    @Override
    public boolean insertById(T t) throws Exception {
        MetaData metaData = IndexTools.getIndexType(t.getClass());
        String indexname = metaData.getIndexname();
        String indextype = metaData.getIndextype();
        String id = Tools.getESId(t);
        IndexRequest indexRequest = null;
        if (StringUtils.isEmpty(id)) {
            indexRequest = new IndexRequest(indexname, indextype);
        } else {
            indexRequest = new IndexRequest(indexname, indextype, id);
        }
        String source = JsonUtils.obj2String(t);
        indexRequest.source(source, XContentType.JSON);
        IndexResponse indexResponse = null;
        indexResponse = client.index(indexRequest, RequestOptions.DEFAULT);
        if (indexResponse.getResult() == DocWriteResponse.Result.CREATED) {
            log.info("INDEX CREATE SUCCESS");
        } else if (indexResponse.getResult() == DocWriteResponse.Result.UPDATED) {
            log.info("INDEX UPDATE SUCCESS");
        } else {
            return false;
        }
        return true;
    }

    @Override
    public boolean update(T t) throws Exception {
        MetaData metaData = IndexTools.getIndexType(t.getClass());
        String indexname = metaData.getIndexname();
        String indextype = metaData.getIndextype();
        String id = Tools.getESId(t);
        if (StringUtils.isEmpty(id)) {
            throw new Exception("ID cannot be empty");
        }
        UpdateRequest updateRequest = new UpdateRequest(indexname, indextype, id);
        updateRequest.doc(Tools.getFieldValue(t));
        UpdateResponse updateResponse = null;
        updateResponse = client.update(updateRequest, RequestOptions.DEFAULT);
        if (updateResponse.getResult() == DocWriteResponse.Result.CREATED) {
            log.info("INDEX CREATE SUCCESS");
        } else if (updateResponse.getResult() == DocWriteResponse.Result.UPDATED) {
            log.info("INDEX UPDATE SUCCESS");
        } else {
            return false;
        }
        return true;
    }

    @Override
    public T getById(String id, Class<T> clazz) throws Exception {
        MetaData metaData = IndexTools.getIndexType(clazz);
        String indexname = metaData.getIndexname();
        String indextype = metaData.getIndextype();
        if (StringUtils.isEmpty(id)) {
            throw new Exception("ID cannot be empty");
        }
        GetRequest getRequest = new GetRequest(indexname, indextype, id);
        GetResponse getResponse = client.get(getRequest, RequestOptions.DEFAULT);
        if (getResponse.isExists()) {
            return JsonUtils.string2Obj(getResponse.getSourceAsString(), clazz);
        }
        return null;
    }

    @Override
    public String getAll(Class<T> clazz) throws Exception {
        List<Message> list = new ArrayList<>();
        elasticsearchRepository.findAll().forEach(list::add);
        return JsonUtil.toJson(list);
    }

    @Override
    public List<Map<String,Object>> search(String fileName, String value, Class<T> clazz) throws Exception {
        QueryBuilder termQuery=QueryBuilders.termQuery(fileName+".keyword",value);
        MetaData metaData = IndexTools.getIndexType(clazz);
        // 设置查询字段
        SearchResponse response = elasticsearchTemplate.getClient().prepareSearch(metaData.getIndexname())
                .setQuery(termQuery)
                .setFrom(0)
                .setSize(10) // 设置一次返回的文档数量，最大值：10
                .get();

        // 返回搜索结果
        SearchHits hits = response.getHits();

        return getHitList(hits);
    }


    @Override
    public Map<String,Object> queryByPage(int pageNo, int pageSize, String keyword, String indexName, String... fieldNames) {
        // 构造查询条件,使用标准分词器.
        QueryBuilder matchQuery = createQueryBuilder(keyword,fieldNames);

        // 设置查询字段
        SearchResponse response = elasticsearchTemplate.getClient().prepareSearch(indexName)
                .setQuery(matchQuery)
                .setFrom((pageNo-1) * pageSize)
                .setSize(pageNo * pageSize) // 设置一次返回的文档数量，最大值：10000
                .get();

        // 返回搜索结果
        SearchHits hits = response.getHits();

        Long totalCount = hits.getTotalHits();
        Page<Map<String, Object>> page = new Page<>(pageNo,pageSize,totalCount.intValue());
        page.setList(getHitList(hits));
        Map<String, Object> map=new HashMap<String, Object>();
        map.put("result",page);
        return map;
    }

    private QueryBuilder createQueryBuilder(String keyword, String... fieldNames){
        // 构造查询条件,使用标准分词器.
        return QueryBuilders.multiMatchQuery(keyword,fieldNames)   // matchQuery(),单字段搜索
//                .analyzer("ik_max_word")
                .operator(Operator.OR);
    }

    private List<Map<String,Object>> getHitList(SearchHits hits){
        List<Map<String,Object>> list = new ArrayList<>();

        for(SearchHit searchHit : hits){
            // 处理源数据
            list.add(searchHit.getSourceAsMap());
        }
        return list;
    }
    @Override
    public long count(Class<T> clazz) {
        SearchQuery searchQuery = new NativeSearchQueryBuilder()
//                .withQuery(new QueryStringQueryBuilder(keyword))
                .withSort(SortBuilders.scoreSort().order(SortOrder.DESC))
                // .withSort(new FieldSortBuilder("createTime").order(SortOrder.DESC))
                .build();
        return elasticsearchTemplate.count(searchQuery,clazz);
    }
}
